<script setup lang="ts">
import {
  ref,
  onMounted,
  onUnmounted,
  nextTick,
  defineEmits,
  reactive,
} from "vue";

const props = defineProps({
  // 刮开占比 当刮奖图层挂到scratchPercent百分比时,移除刮奖图层
  scratchPercent: {
    type: Number,
    default: 80,
  },
  handImageUrl: {},
  // 涂层图
  imageUrl: {
    type: String,
  },
  // 涂层颜色
  maskColor: {
    type: String,
    default: "#cccccc",
  },
  // 刮奖背景色
  fillStyle: {
    type: String,
    default: "#000000",
  },
  // 刮奖字体
  font: {
    type: String,
    default: "18px Arial",
  },
  // 涂层文字
  text: {
    type: String,
    default: "刮一刮",
  },
  // 圆角
  radius: {
    type: Number,
    default: 0,
  },
  // 刮奖半径
  scratchRadius: {
    type: Number,
    default: 10,
  },
});
const emit = defineEmits(["scratchStart", "scratchEnd", "scratchAll"]);
const ctx = ref<CanvasRenderingContext2D | null | undefined>(null);
const slot = ref<HTMLInputElement | null>(null);
const canvas = ref<HTMLCanvasElement | null>(null);
const width = ref(0);
const height = ref(0);
const isScratching = ref(false);

const handStyle = reactive({
  left: "0px",
  top: "0px",
});
const init = () => {
  initCanvas();
  nextTick(() => {
    initDraw();
    bindEvents();
  });
};

const initCanvas = () => {
  width.value = slot.value?.offsetWidth || 0;
  height.value = slot.value?.offsetHeight || 0;
};
//初始化绘制
const initDraw = () => {
  ctx.value = canvas.value?.getContext("2d");
  if (ctx.value) {
    ctx.value.globalAlpha = 1;
    ctx.value.fillStyle = props.maskColor;
    //绘制圆角
    if (props.radius) {
      const radius = props.radius;
      //使用clip剪切出圆角
      ctx.value.beginPath();
      //左上角圆角
      ctx.value.moveTo(radius, 0);
      ctx.value.arcTo(0, 0, 0, radius, radius);
      //左下角圆角
      ctx.value.lineTo(0, height.value - radius);
      ctx.value.arcTo(0, height.value, radius, height.value, radius);
      //右下角圆角
      ctx.value.lineTo(width.value - radius, height.value);
      ctx.value.arcTo(
        width.value,
        height.value,
        width.value,
        height.value - radius,
        radius
      );
      //右上角圆角
      ctx.value.lineTo(width.value, radius);
      ctx.value.arcTo(width.value, 0, width.value - radius, 0, radius);
      ctx.value.closePath();
      ctx.value.clip();
    }
    ctx.value.fillRect(0, 0, width.value, height.value);
    //若没有图片绘制文本
    if (!props.imageUrl) {
      // 文本
      ctx.value.fillStyle = props.fillStyle;
      ctx.value.font = props.font;
      // ctx.textAlign = "center";
      // ctx.textBaseline = "middle";

      // 绘制文字
      let text = props.text;
      let textWidth = ctx.value.measureText(text).width;
      let x = width.value / 2 - textWidth / 2;
      let y = height.value / 2 + 6;

      ctx.value.fillText(text, x, y);
    }

    //绘制图片
    if (props.imageUrl) {
      // 创建 Image 对象
      const img = new Image();

      // 设置图片URL
      img.src = props.imageUrl;

      // 监听图片加载完成事件
      img.onload = () => {
        //确定圆角半径

        // 在 Canvas 上绘制图片
        ctx.value?.drawImage(img, 0, 0, width.value, height.value);
      };
    }
  }
};
// 手指坐标
const handAxis = (e) => {
  const touch = e.touches[0];
  const x =
    touch.clientX - slot.value?.offsetParent?.offsetParent?.offsetLeft - 25;
  const y = touch.clientY - slot?.value?.offsetParent?.offsetParent?.offsetTop - 25;

  if (x > 0 && x < width.value) {
    handStyle.left = x + "px";
  } else if (x < 0) {
    handStyle.left = 0 + "px";
  } else if (x > width.value) {
    handStyle.left = width.value + "px";
  }

  if (y > 0 && y < height.value) {
    handStyle.top = y + "px";
  } else if (y < 0) {
    handStyle.top = 0 + "px";
  } else if (y > height.value) {
    handStyle.top = height.value + "px";
  }
};
//绑定事件
const bindEvents = () => {
  if (!canvas.value) {
    return;
  }
  // pc
  canvas.value.addEventListener("mousedown", (e) => {
    isScratching.value = true;
    drawArc(e);
    console.log("mousedown");
  });
  canvas.value.addEventListener("mousemove", (e) => {
    if (isScratching.value == true) {
      drawArc(e);
    }

    console.log("mousemove");
  });
  canvas.value.addEventListener("mouseup", () => {
    isScratching.value = false;
    calcArea();
    console.log("mouseup");
  });
  // wap
  canvas.value.addEventListener("touchstart", (e) => {
    emit("scratchStart");
    isScratching.value = true;

    console.log("touchstart");
    handAxis(e);
    drawArc(e);
  });
  canvas.value.addEventListener("touchmove", (e) => {
    console.log("touchstart");
    handAxis(e);
    if (isScratching.value == true) {
      drawArc(e);
    }
  });
  canvas.value.addEventListener("touchend", () => {
    console.log("touchstart");

    isScratching.value = false;
    emit("scratchEnd");
    calcArea();
  });
};
// 刮开区域
const drawArc = (e: MouseEvent | TouchEvent) => {
  if (!canvas.value || !ctx.value) {
    return;
  }
  const canvasPos = canvas.value.getBoundingClientRect();
  const pageScrollTop =
    document.documentElement.scrollTop || document.body.scrollTop;
  const pageScrollLeft =
    document.documentElement.scrollLeft || document.body.scrollLeft;
  let mouseX = 0;
  let mouseY = 0;

  if (e instanceof MouseEvent) {
    mouseX = e.pageX - canvasPos.left - pageScrollLeft;
    mouseY = e.pageY - canvasPos.top - pageScrollTop;
  } else if (e instanceof TouchEvent) {
    mouseX = e.targetTouches[0].pageX - canvasPos.left - pageScrollLeft;
    mouseY = e.targetTouches[0].pageY - canvasPos.top - pageScrollTop;
  } else {
    return;
  }

  ctx.value.globalCompositeOperation = "destination-out";
  ctx.value.beginPath();
  ctx.value.fillStyle = "white";
  ctx.value.moveTo(mouseX, mouseY);
  ctx.value.arc(mouseX, mouseY, props.scratchRadius, 0, 3 * Math.PI);
  ctx.value.fill();
};

//重置刮刮乐
const reset = () => {
  width.value = 0;
  height.value = 0;
  nextTick(() => {
    init();
  });
};

// 计算区域
const calcArea = () => {
  if (!canvas.value || !ctx.value) {
    return;
  }
  let myImg = ctx.value.getImageData(0, 0, width.value, height.value);
  let num = 0;
  let max = myImg.data.length / 4;
  for (let i = 0; i < myImg.data.length; i += 4) {
    if (myImg.data[i + 3] == 0) {
      num++;
    }
  }
  if (num >= max * (props.scratchPercent / 100)) {
    canvas.value.remove();
    emit("scratchAll");
  }
};
//重绘
const onResize = () => {
  ctx.value = null;
  init();
};

onMounted(() => {
  init();
  window.addEventListener("resize", onResize);
});
onUnmounted(() => {
  window.removeEventListener("resize", onResize);
});
defineExpose({
  reset,
});
</script>

<template>
  <div class="box">
    <div ref="slot" class="slot" :style="{ borderRadius: radius + 'px' }">
      <slot></slot>
    </div>
    <canvas
      v-if="width && height"
      class="canvas"
      ref="canvas"
      :width="width"
      :height="height"
    ></canvas>
    <img
      class="hand-image"
      :style="handStyle"
      src="../assets/image/hand.png"
      alt=""
    />
  </div>
</template>

<style scoped>
.box {
  position: relative;
  display: inline-block;
}

.slot {
  display: inline-block;
  overflow: hidden;
}

.canvas {
  position: absolute;
  top: 0;
  left: 0;
}

.hand-image {
  position: absolute;
  left: 0;
  top: 0;
  width: 50px;
  height: 50px;
}
</style>
